require 'digest/sha1'
class User < ActiveRecord::Base
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessor :login, :password, :password_confirmation
  attr_accessible :email, :password, :password_confirmation, :firstname, :lastname, :account_number, :image, :mail_declaration, :mail_deposit, :mail_postit, :mail_balance
  
  before_save :encrypt_password
  
  MAX_DEBT = Money.new(150.00)
  MINIMUM_PASSPHRASE_LENGTH     = 8
  MAXIMUM_PASSPHRASE_LENGTH     = 64
  IMAGES_DIR = RAILS_ROOT + '/public/images/users' 
  
  has_many :declaration_payers
  has_many :declarations
  has_many :deposits_from, :class_name => 'Deposit', :foreign_key => 'from_user_id', :order => 'created_at desc'
  has_many :deposits_to, :class_name => 'Deposit', :foreign_key => 'to_user_id', :order => 'created_at desc'
  
  validates_format_of       :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :message => '^Geen geldig e-mailadres ingevuld'
  
  validates_presence_of     :firstname, :message => "^Voornaam is niet ingevuld"
  validates_presence_of     :lastname, :message => "^Achternaam is niet ingevuld"
  validates_presence_of     :email, 
                            :message => "is een verplicht veld"
  validates_presence_of     :password, 
                            :if => :password_required?,
                            :message =>  "^Geen wachtwoord ingevuld"
  validates_presence_of     :password_confirmation,      :if => :password_required?
  validates_length_of       :password, 
                            :within => MINIMUM_PASSPHRASE_LENGTH..MAXIMUM_PASSPHRASE_LENGTH, 
                            :if => :password_required?, 
                            :too_long	 => "Het wachtwoord mag maximaal %d tekens lang zijn",
                            :too_short => "^Het wachtwoord moet minimaal %d tekens lang zijn"
  validates_confirmation_of :password,
                            :if => :password_required?, 
                            :message => "^De wachtwoorden komen niet overeen"
                          
  validates_length_of       :email,    :within => 3..100
  validates_uniqueness_of   :email, 
                            :case_sensitive => false
  validates_uniqueness_of   :account_number, 
                            :if => :account_number?
  
  def login
    self.to_i
  end
  
  def to_i
    self.id.to_i
  end
  
  def self.count_active(*args)
    options = args.extract_options!
    
    if not options[:conditions]
      options[:conditions] = Hash.new
    end
    
    options[:conditions][:active] = true
    args << options
    count(*args)
  end
  
  def fullname
    self.firstname + ' ' + self.lastname
  end

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  def self.authenticate(login, password)
    
    u = find_by_id(login) # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end

  # Encrypts some data with the salt.
  def self.encrypt(password, salt)
    Digest::SHA1.hexdigest("--#{salt}--#{password}--")
  end

  # Encrypts the password with the user salt
  def encrypt(password)
    self.class.encrypt(password, salt)
  end

  def authenticated?(password)
    crypted_password == encrypt(password)
  end

  def remember_token?
    remember_token_expires_at && Time.now.utc < remember_token_expires_at 
  end

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    remember_me_for 2.weeks
  end

  def remember_me_for(time)
    remember_me_until time.from_now.utc
  end

  def remember_me_until(time)
    self.remember_token_expires_at = time
    self.remember_token            = encrypt("#{email}--#{remember_token_expires_at}")
    save(false)
  end

  def forget_me
    self.remember_token_expires_at = nil
    self.remember_token            = nil
    save(false)
  end
  
  #Eigen
  
  def account_number?
    return false if account_number.nil? or account_number.empty?
    true
  end
  
  def getAdditionalpersonsForDeclaration(declaration_id)
    declarations_payer = self.declaration_payers.find_by_declaration_id(declaration_id)
    
    if !declarations_payer.nil?
      return declarations_payer.additional_persons
    end
  end
  
  def image
    #require 'uri'
    image =  Dir.new(IMAGES_DIR).entries.map! { |x| x =~ /^#{self.firstname}/ ? x : next  }.compact.first
    return "users/#{image}"
  end
  
  def balance()
    pay = Money.new(0)
    paid = Money.new(0)
    deposits_in = Money.new(0)
    deposits_out = Money.new(0)
    
    #1. Verzamel alle declaraties waaraan die bewoner heeft meebetaald
    for declaration_payer in self.declaration_payers
      #2. Van iedere declaratie opvragen hoeveel je moet meebetalen
      pay = pay + declaration_payer.declaration.share(self)
    end
    
    #We weten nu hoeveel de bewoner in totaal moet betalen,
    #maar waarschijnlijk heeft deze al wat gekocht
    for declaration in self.declarations
      #3. En opvragen hoeveel je hebt betaald
      paid += declaration.amount
    end

    #4. Tel alle declaraties op die de bewoner heeft ingediend
    
    #Alle stortingen die deze persoon ontvangen heeft, misschien nog abstraheren? Want confirmed??
    deposits_in = Deposit.sum(:amount, :conditions => {:to_user_id => self.id, :confirmed => true}) || 0.0
    
    #Alle stortingen die deze persoon betaald heeft, misschien nog abstraheren? Want confirmed??
    deposits_out = Deposit.sum(:amount, :conditions => {:from_user_id => self.id, :confirmed => true}) || 0.0
    
    total = -pay + paid - deposits_in + deposits_out
    
    return Money.new(total)
  end

  def self.get_all_active_except(user)
    find(:all, :conditions => ["id != ? AND active = ?", user.id, true])
  end
  
  def self.get_all_active
    find(:all, :conditions => ["active = ?", true])
  end
  
  def image=(image)
    require 'rake/contrib/sys'

    return if image.nil? || image.to_s.empty?
    
    if !/^image/.match(image.content_type)
      errors.add(:image, '^Het moet wel een plaatje zijn!')
      return false
    end
  	
    extension = image.original_filename.scan(/.*\.(.*)/).last
    path = IMAGES_DIR
    path = path.rtrim('/')
    path = IMAGES_DIR + "/#{firstname}.#{extension}"

    #Remove the old image (just to make sure)
    Sys.delete_all("#{IMAGES_DIR}/#{firstname}.*")

    File.open(path, 'wb') do |file|
      file.puts image.read
    end
  end
  
  def self.send_mail_for_users_with_high_debts
    users = User.get_all_active
    
    users.each do |user|
      Mailer.deliver_notify_about_balans(user) if user.debt_to_high?
    end
  end
  
  def debt_to_high?
    self.balance.to_i < (MAX_DEBT.to_i.abs)
  end
  
  protected
    # before filter 
    def encrypt_password
      return if password.blank?
      self.salt = create_salt if new_record?
      self.crypted_password = encrypt(password)
    end
      
    def password_required?
      crypted_password.blank? || !password.blank?
    end
    
    def create_salt
      #Digest::SHA1.hexdigest("--#{Time.now.to_i}--#{login}--")
      Digest::MD5.hexdigest("--#{Time.now.to_i}--#{login}--")
    end
  
private
end